package com.koicarp.university.graudate.common.utils;

import com.alibaba.fastjson.JSONArray;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.rdf.model.Property;
import org.apache.jena.rdf.model.Resource;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Workbook;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Author xiewenquan
 * @Date 2020-04-21
 * 下载文件工具类
 */
@Slf4j
public class DownLoadUtil {

	private DownLoadUtil(){}

	/**
	 * 写入数据到指定Excel中
	 * @param headers 表头信息
	 * @param dataList 数据集合
	 * @param path excel路径
	 * @param dataNum 每个sheet页的数据量
	 * @return
	 */
	public static boolean writeDataToExcel(String[] headers, List<Object[]> dataList, String path,int dataNum,int startIndex) {
		/*if (dataNum < 1){
			log.error("每个sheet页的数据量不能小于1",new RuntimeException("每个sheet页的数据量不能小于1"));
			return false;
		}*/

		/*
		if (dataList == null){
			dataList = new ArrayList<>();
		}
		Workbook workbook = ExcelUtil.writeExcel(headers,dataList,dataNum,startIndex);
		OutputStream out = null;
		try {
			out = new FileOutputStream(path);
			workbook.write(out);
			out.flush();
		} catch (Exception e){
			log.error("写数据到Excel出错",e);
			return false;
		} finally {
			try {
				if (out != null){
					out.close();
				}
				if (workbook != null){
					workbook.close();
				}
			} catch (Exception e){
				log.error("写数据到Excel出错",e);
			}
		}

		return true;
		 */
		return writeDataToExcel(headers,dataList,path,dataNum,startIndex,null);
	}

	/**
	 * 写入数据到指定Excel中(表格有下拉选情况适用)
	 * @param headers 表头信息
	 * @param dataList 数据集合
	 * @param path excel路径
	 * @param dataNum 每个sheet页的数据量
	 * @return
	 */
	public static boolean writeDataToExcel(String[] headers, List<Object[]> dataList, String path, int dataNum, int startIndex, Map<Integer,String[]> dropDownMap) {
		/*if (dataNum < 1){
			log.error("每个sheet页的数据量不能小于1",new RuntimeException("每个sheet页的数据量不能小于1"));
			return false;
		}*/
		if (dataList == null){
			dataList = new ArrayList<>();
		}
		//boolean xlsx = path.endsWith("xlsx");
		Workbook workbook = ExcelUtil.writeExcel(headers,dataList,dataNum,startIndex,dropDownMap);
		OutputStream out = null;
		try {
			out = new FileOutputStream(path);
			workbook.write(out);
			out.flush();
		} catch (Exception e){
			log.error("写数据到Excel出错",e);
			return false;
		} finally {
			try {
				if (out != null){
					out.close();
				}
				if (workbook != null){
					workbook.close();
				}
			} catch (Exception e){
				log.error("写数据到Excel出错",e);
			}
		}

		return true;
	}


	/**
	 * 写入数据则注意数据逗号分隔的格式
	 * @param headers 表头信息
	 * @param dataList 数据集合
	 * @param path 文件路径
	 * @param chartsetName 文件编码格式,默认utf8
	 * @return
	 */
	public static boolean wirteDataToCsv(String[] headers, List<Object[]> dataList, String path,String chartsetName){
		BufferedWriter writer = null;
		OutputStreamWriter out = null;
		/*if(chartsetName == null || "".equals(chartsetName)){
			chartsetName="UTF8";
		}*/
		try{
			File file = new File(path);
			if (UniversityUtil.isNotNull(chartsetName)){
				out = new OutputStreamWriter( new FileOutputStream(file), chartsetName);
			} else {
				out = new OutputStreamWriter( new FileOutputStream(file));
			}

			writer = new BufferedWriter(out);

			if (headers != null && headers.length > 0){
				StringBuffer headerLine = new StringBuffer("");
				for (int i = 0;i < headers.length;i++){
					if(i != 0){
						headerLine.append(",");
					}
					headerLine.append(UniversityUtil.convertNull2Blank(headers[i]));
				}
				writer.write(headerLine.toString());
				writer.newLine();
			}

			if(dataList != null && dataList.size() > 0){
				for (Object[] data : dataList){
					StringBuffer dataLine = new StringBuffer("");
					for (int i = 0;i < data.length;i++){
						if (i != 0){
							dataLine.append(",");
						}
						dataLine.append(UniversityUtil.convertNull2Blank(String.valueOf(data[i])));
					}
					writer.write(dataLine.toString());
					writer.newLine();
				}
			}
			writer.flush();
		}catch (Exception e){
			log.error(e.getMessage(),e);
			return false;
		} finally {
			try {
				if (out != null){
					out.close();
				}
				if (writer != null){
					writer.close();
				}
			} catch (IOException e) {
				log.error(e.getMessage(),e);
			}

		}
		return true;
	}


	/**
	 * 将数据写入到JSON文件中去
	 * @param headers 表头信息
	 * @param dataList 数据集合
	 * @param path json文件路径
	 * @param chartsetName 编码名称
	 * @return
	 */
	public static boolean writeDataToJson(String[] headers, List<Object[]> dataList, String path,String chartsetName){
		/*if(chartsetName == null || "".equals(chartsetName)){
			chartsetName="UTF8";
		}*/
		int dataLength = dataList == null ? 0 : dataList.size();
		Object[] jsonArray = new Object[1+dataLength];
		if (headers != null && headers.length > 0){
			jsonArray[0] = headers;
		}
		if (dataList != null && dataList.size() > 0){
			for (int i = 0;i < dataList.size();i++){
				jsonArray[i+1] = dataList.get(i);
			}
		}
		BufferedWriter writer = null;
		OutputStreamWriter out = null;
		try{
			File file = new File(path);
			if (UniversityUtil.isNotNull(chartsetName)){
				out = new OutputStreamWriter( new FileOutputStream(file), chartsetName);
			} else {
				out = new OutputStreamWriter( new FileOutputStream(file));
			}
			writer = new BufferedWriter(out);
			String jsonStr = JSONArray.toJSONString(jsonArray);
			writer.write(jsonStr);
			writer.flush();
		} catch (Exception e){
			log.error(e.getMessage(),e);
			return false;
		} finally {
			try {
				if(writer != null){
					writer.close();
				}
				if(out != null){
					out.close();
				}
			} catch (IOException e) {
				log.error(e.getMessage(),e);
			}
		}
		return true;
	}

	/**
	 * 将数据写入到XML文件中去
	 * @param headers 表头信息
	 * @param dataList 数据集合
	 * @param path 文件路径
	 * @param chartsetName 编码名称
	 * @return
	 */
	public static boolean writeDataToXml(String[] headers, List<Object[]> dataList, String path, String chartsetName){
		Document dom = DocumentHelper.createDocument();
		Element listElement = dom.addElement("list");
		for (Object[] data : dataList){
			Element mapElemnt = listElement.addElement("map");
			for(int i = 0;i < headers.length;i++){
				mapElemnt.addElement(headers[i]).setText(String.valueOf(data[i]));
			}
		}
		OutputFormat format = OutputFormat.createPrettyPrint();
		if (UniversityUtil.isNotNull(chartsetName)){
			format.setEncoding(chartsetName);
		}
		File file = new File(path);
		XMLWriter writer = null;
		try {
			writer = new XMLWriter(new FileOutputStream(file),format);
			writer.setEscapeText(false); //关闭字符串中xml特殊字符转义
			writer.write(dom);
			writer.flush();
		} catch (Exception e){
			log.error(e.getMessage(),e);
			return false;
		} finally {
			if (writer != null){
				try {
					writer.close();
				} catch (IOException e) {
					log.error(e.getMessage(),e);
				}
			}
		}
		return true;
	}

	/**
	 * 将数据写入到RDF文件中去
	 * @param headers 表头信息
	 * @param dataList 数据集合
	 * @param path 文件路径
	 * @param nsPrefix 命名空间前缀
	 * @param namespace 命名空间
	 * @return
	 */
	public static boolean writeDataToRdf(String[] headers, List<Object[]> dataList, String path,String nsPrefix,String namespace){
		Model model = ModelFactory.createDefaultModel();
		model.setNsPrefix(nsPrefix,namespace);
		if (headers == null || headers.length == 0){
			log.error("数据列信息不能为空!!!");
			return false;
		}
		for (Object[] data : dataList){
			Resource resource = model.createResource();
			for (int i = 0; i < headers.length;i++){
				Property property = model.createProperty(namespace+headers[i]);
				resource.addProperty(property,String.valueOf(data[i]));
			}
		}
		//model.write(System.out);
		OutputStreamWriter out = null;
		BufferedWriter writer = null;
		try{
			File file = new File(path);
			out = new OutputStreamWriter( new FileOutputStream(file));
			writer = new BufferedWriter(out);
			model.write(writer);
			writer.flush();
		} catch (Exception e){
			log.error(e.getMessage(),e);
			return false;
		} finally {
			try {
				if (out != null){
					out.close();
				}
				if (writer != null){
					writer.close();
				}
			} catch (IOException e) {
				log.error(e.getMessage(),e);
			}
		}
		return true;
	}

	/**
	 * 下载文件
	 * @param path 文件路径
	 * @param response 响应对象
	 */
	public static void downloadFile(String path, HttpServletResponse response) throws Exception{
		if (path == null || "".equals(path)){
			log.error("path不可为空!!");
			return;
		}
		File file = new File(path);
		String filename = file.getName();
		response.reset();
		response.setHeader("Access-Control-Allow-Origin", "*");
		response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename,"utf-8"));
		response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
		response.setCharacterEncoding("utf-8");
		FileUtils.copyFile(file,response.getOutputStream());
	}

	/**
	 * 下载文件
	 * @param in 文件输入流
	 * @param response 响应对象
	 * @param filename 文件名
	 */
	public static void downloadFile(InputStream in, HttpServletResponse response,String filename) throws Exception{

		OutputStream out = null;
		try{
			byte[] buffer = new byte[in.available()];
			in.read(buffer);
			response.reset();
			response.setHeader("Access-Control-Allow-Origin", "*");
			response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename,"utf-8"));
			//response.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
			response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
			response.setCharacterEncoding("utf-8");
			out = new BufferedOutputStream(response.getOutputStream());
			out.write(buffer);
			out.flush();
		} catch (Exception e){
			log.error(e.getMessage(),e);
			throw e;
		} finally {
			try {
				if (in != null){
					in.close();
				}
				if (out != null){
					out.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

	/**
	 * 下载文件
	 * @param buffer 数据 byte数组
	 * @param response 响应对象
	 */
	public static void downloadFile(byte[] buffer, HttpServletResponse response,String filename) throws Exception{
		OutputStream out = null;
		try{
			response.reset();
			response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename,"utf-8"));
			response.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
			response.setCharacterEncoding("utf-8");
			out = new BufferedOutputStream(response.getOutputStream());
			out.write(buffer);
			out.flush();
		} catch (Exception e){
			log.error(e.getMessage(),e);
			throw e;
		} finally {
			try {
				if (out != null){
					out.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

	/**
	 * 根据表头列表，生成excel文件
	 * @param list 表头列表
	 * @param modelName 文件名
	 * @param modelPath 文件路径
	 */
	public static boolean createModel(List<String> list, String modelName, String modelPath) {
		boolean newFile = false;
        //创建excel工作簿
		HSSFWorkbook workbook = new HSSFWorkbook();
		//创建工作表sheet
		HSSFSheet sheet = workbook.createSheet();
        //创建第一行
		HSSFRow row = sheet.createRow(0);
		HSSFCell cell;
        //设置样式
		CellStyle style = workbook.createCellStyle();
		style.setFillForegroundColor(IndexedColors.AQUA.getIndex());

        //插入第一行数据的表头
		for (int i = 0; i < list.size(); i++) {
			cell = row.createCell(i);
			cell.setCellStyle(style);
			cell.setCellValue(list.get(i));
		}
        //创建excel文件
		File file = new File(modelPath + File.separator + modelName);
		try {
           //删除该文件夹下原来的模版文件
			//deleteDir(new File(modelPath + File.separator));
            //判断对应的文件夹是否有，无则新建
			File myPath = new File(modelPath);
			if (!myPath.exists()) {
				myPath.mkdir();
			}
            //创建新的模版文件
			newFile = file.createNewFile();
			//将excel写入
			FileOutputStream stream = FileUtils.openOutputStream(file);
			workbook.write(stream);
			stream.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return newFile;
	}

	/**
	 * 删除路径下的模板文件
	 * @param dir 路径
	 */
	private static boolean deleteDir(File dir) {
		if (dir.isDirectory()) {
			String[] children = dir.list();
			if (children != null)
				//递归删除目录中的子目录下
				for (String child : children) {
					boolean success = deleteDir(new File(dir, child));
					if (!success) {
						return false;
					}
				}
		}
		// 目录此时为空，可以删除
		return dir.delete();
	}

	/**
	 * 动态下载模板
	 * @param filePath 服务器上文件路径
	 * @param fileName 服务器上文件名
	 * @param newName 下载文件名
	 */
	public static ResponseEntity<InputStreamResource> download(String filePath, String fileName, String newName) {
		String path;
		ResponseEntity<InputStreamResource> response = null;
		try {
			//path = filePath + File.separator + fileName;
			path = filePath + fileName;
			log.info("下载的路径为-->[{}]", path);
			File file = new File(path);
			InputStream inputStream = new FileInputStream(file);
			HttpHeaders headers = new HttpHeaders();
			headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
			headers.add("Content-Disposition",
					"attachment; filename="
							+ new String(newName.getBytes(StandardCharsets.UTF_8)));
			headers.add("Pragma", "no-cache");
			headers.add("Expires", "0");
			response = ResponseEntity.ok().headers(headers)
					.contentType(MediaType.parseMediaType("application/octet-stream"))
					.body(new InputStreamResource(inputStream));
		} catch (FileNotFoundException e1) {
			log.error("找不到指定的文件", e1);
		}
		return response;
	}

}
